class TreeView {
  constructor($dom, store, adapter) {
    this.store = store
    this.adapter = adapter
    this.$view = $dom.find('.octotree_treeview')
    var _that = this;
    this.$tree = this.$view.find('.octotree_view_body')
      // .on('click.jstree', '.jstree-open>a', ({target}) => this.$jstree.close_node(target))
      // .on('click.jstree', '.jstree-closed>a', ({target}) => this.$jstree.open_node(target))
      .on('click', this._onItemClick.bind(this))
      .jstree({
        core: {multiple: false, worker: false, themes: {responsive: false}}, plugins: ['wholerow', 'contextmenu']
      })
  }

  get $jstree() {
    return this.$tree.jstree(true)
  }

  show(repo, token) {
    const $jstree = this.$jstree

    $jstree.settings.core.data = (node, cb) => {
      const prMode = this.store.get(STORE.PR) && repo.pullNumber
      const loadAll = this.adapter.canLoadEntireTree() && (prMode || this.store.get(STORE.LOADALL))

      node = !loadAll && (node.id === '#' ? {path: ''} : node.original)

      this.adapter.loadCodeTree({repo, token, node}, (err, treeData) => {
        if (err) {
          $(this).trigger(EVENT.FETCH_ERROR, [err])
        } else {
          treeData = this._sort(treeData)
          if (loadAll) {
            treeData = this._collapse(treeData)
          }
          cb(treeData)
        }
      })
    }

    this.$tree.one('refresh.jstree', () => {
      this.syncSelection()
      $(this).trigger(EVENT.VIEW_READY)
    })

    this._showHeader(repo)
    $jstree.refresh(true)
  }

  _showHeader(repo) {
    const adapter = this.adapter

    this.$view.find('.octotree_view_header')
      .html('<div class="octotree_header_repo">' + '<a href="/' + repo.username + '">' + repo.username + '</a>' + ' / ' + '<a data-pjax href="/' + repo.username + '/' + repo.reponame + '">' + repo.reponame + '</a>' + '</div>' + '<div class="octotree_header_branch">' + this._deXss(repo.branch.toString()) + '</div>')
      .on('click', 'a[data-pjax]', function (event) {
        event.preventDefault()
        const href = $(this).attr('href'); /* a.href always return absolute URL, don't want that */
        const newTab = event.shiftKey || event.ctrlKey || event.metaKey
        newTab ? adapter.openInNewTab(href) : adapter.selectFile(href)
      })
  }

  _deXss(str) {
    return str && str.replace(/[<>'"&]/g, '-')
  }

  _sort(folder) {
    folder.sort((a, b) => {
      if (a.type === b.type) return a.text === b.text ? 0 : a.text < b.text ? -1 : 1
      return a.type === 'blob' ? 1 : -1
    })

    folder.forEach((item) => {
      if (item.type === 'tree' && item.children !== true && item.children.length > 0) {
        this._sort(item.children)
      }
    })

    return folder
  }

  _collapse(folder) {
    return folder.map((item) => {
      if (item.type === 'tree') {
        item.children = this._collapse(item.children)
        if (item.children.length === 1 && item.children[0].type === 'tree') {
          const onlyChild = item.children[0]
          onlyChild.text = item.text + '/' + onlyChild.text
          return onlyChild
        }
      }
      return item
    })
  }

  _onItemClick(event) {
    let $target = $(event.target)
    let download = false

    // handle middle click
    if (event.which === 2) return

    // handle icon click, fix #122
    if ($target.is('i.jstree-icon')) {
      $target = $target.parent()
      download = true
    }

    if (!$target.is('a.jstree-anchor')) return

    // refocus after complete so that keyboard navigation works, fix #158
    const refocusAfterCompletion = () => {
      $(document).one('pjax:success page:load', () => {
        this.$jstree.get_container().focus()
      })
    }

    const adapter = this.adapter
    const newTab = event.shiftKey || event.ctrlKey || event.metaKey
    const href = $target.attr('href')
    const $icon = $target.children().length ? $target.children(':first') : $target.siblings(':first') // handles child links in submodule

    if ($icon.hasClass('commit')) {
      refocusAfterCompletion()
      newTab ? adapter.openInNewTab(href) : adapter.selectSubmodule(href)
    } else if ($icon.hasClass('blob')) {
      if (download) {
        const downloadUrl = $target.attr('data-download-url')
        const downloadFileName = $target.attr('data-download-filename')
        adapter.downloadFile(downloadUrl, downloadFileName)
      } else {
        refocusAfterCompletion()
        newTab ? adapter.openInNewTab(href) : adapter.selectFile(href)
      }
    } else if ($icon.hasClass('tree') && download) {
      this._downAll($target)
    }
  }

  syncSelection() {
    const $jstree = this.$jstree
    if (!$jstree) return

    // converts /username/reponame/object_type/branch/path to path
    const path = decodeURIComponent(location.pathname)
    const match = path.match(/(?:[^\/]+\/){4}(.*)/)
    if (!match) return

    const currentPath = match[1]
    const loadAll = this.adapter.canLoadEntireTree() && this.store.get(STORE.LOADALL)

    selectPath(loadAll ? [currentPath] : breakPath(currentPath))

    // converts ['a/b'] to ['a', 'a/b']
    function breakPath(fullPath) {
      return fullPath.split('/').reduce((res, path, idx) => {
        res.push(idx === 0 ? path : (res[idx - 1] + '/' + path))
        return res
      }, [])
    }

    function selectPath(paths, index = 0) {
      const nodeId = NODE_PREFIX + paths[index]

      if ($jstree.get_node(nodeId)) {
        $jstree.deselect_all()
        $jstree.select_node(nodeId)
        $jstree.open_node(nodeId, () => {
          if (++index < paths.length) {
            selectPath(paths, index)
          }
        })
      }
    }
  }

  _downAll(data) {
    let div = document.createElement('div');
    $(div).attr('id', 'zzzzzzzzzzzzzzzzz');
    $(div).css({
      'position': 'fixed',
      'top': '0',
      'right': '0',
      'bottom': '0',
      'left': '0',
      'background-color': 'rgb(0 0 0 / 79%)',
      'z-index': '999999999999999999999999999999',
      'text-align': 'center',
      'padding-top': '20%'
    });
    let divTxt = document.createElement('div');
    $(divTxt).text('正在下载中。。。');
    $(divTxt).css({
      'font-size': '30px'
    });

    // <div style="background-color: rgb(30 30 30);height: 200px;width: 800px;margin-left: 28%;margin-top: 5%;position: absolute;" ne="0.651847695504393"></div>
    var dText = document.createElement('div');
    $(dText).attr('id', 'divTxt1111111111');
    $(dText).css({
      'background-color': 'rgb(30 30 30)',
      'height': '200px',
      'width': '800px',
      'margin-left': '28%',
      'margin-top': '5%',
      'position': 'absolute',
      'font-size': '15px',
      'text-align': 'left',
      'overflow-y': 'scroll',
      'color': 'cyan'
    })

    $(divTxt).append(dText);
    $(div).append(divTxt);
    $('html').append(div);
    var that = this;
    //
    // let inst = $.jstree.reference(data.reference);
    //  let obj = that.$jstree.open_node(data)
    $('#divTxt1111111111').html('正在初始化代码树......')
    that.$jstree.load_all(data, function () {
      that.$jstree.open_all(data);

      var id = $(data).parent().attr('id');
      let list = $(document.getElementById(id)).find('a');
      let urlArr = [];
      for (let i = 0; i < list.length; i++) {
        let obj = list[i];
        let downloadUrl = $(obj).attr('data-download-url');
        downloadUrl = downloadUrl.replace(/\/blob\/|\/src\//, '/raw/');
        let downloadFileName = $(obj).attr('data-download-filename');
        let tree = $(obj).find(' .tree');
        let urlObj = {
          downloadUrl: downloadUrl,
          downloadFileName: downloadFileName,
          isFolder: tree.length > 0, // true:文件夹
          id: $(obj).attr('id')
        };
        urlArr.push(urlObj);
      }

      function urlToBlob(the_url, callback) {
        let xhr = new XMLHttpRequest();
        xhr.open("get", the_url, true);
        xhr.responseType = "blob";
        xhr.onload = function () {
          if (this.status == 200) {
            if (callback) {
              callback(this.response);
            }
          }
        };
        xhr.send();
      }

      const zip = new JSZip();
      let falg = 0;

      function down() {
        if (falg < urlArr.length) {
          let url = urlArr[falg];
          if (url.isFolder) {
            let path = url.id.replace('octotree', '').replace('_anchor', '');
            let folder = zip.folder('/' + path);
            falg++;
            //folder.file("文件夹里的文件.txt", '文件夹里的文件-----文件内容');
            down();
          } else {
            $('#divTxt1111111111').html( $('#divTxt1111111111').html()+'<br/>下载文件：'+ url.downloadUrl)
            var scrollHeight = $('#divTxt1111111111').prop("scrollHeight");
            $('#divTxt1111111111').animate({scrollTop:scrollHeight}, 10);


            urlToBlob(url.downloadUrl, function (data) {
              let path = url.id.replace('octotree', '').replace('_anchor', '');
              zip.file('/' + path, data);
              falg++;
              down();
            });
          }
        } else {
          $('#divTxt1111111111').html( $('#divTxt1111111111').html()+'<br/>合并压缩文件：'+ $(data).text() + ".zip")
          zip.generateAsync({type: "blob"}).then(function (content) {
            saveAs(content, $(data).text() + ".zip");
            $('#divTxt1111111111').html($('#divTxt1111111111').html() + '<br/>下载完成：' + $(data).text() + ".zip")
            var scrollHeight = $('#divTxt1111111111').prop("scrollHeight");
            $('#divTxt1111111111').animate({scrollTop:scrollHeight}, 10);
//<button id="divTxt1111111111" style="background-color: rgb(155 155 155);margin-left: -11%;position: absolute;width: 70px;height: 30px;margin-top: 20%;font-size: 15px;color: black;border: 0;" ne="0.72129785252193">关闭</button>
            var button = document.createElement('button');
            $(button).css({
              'background-color': 'rgb(155 155 155)',
              'margin-left': '-11%',
              'position': 'absolute',
              'width': '70px',
              'height': '30px',
              'margin-top': '20%',
              'font-size': '15px',
              'color': 'cyan',
              'border': '0'
            })
            $(button).text('关闭')
            $(divTxt).append(button);
            $(button).click(function () {
              $('#zzzzzzzzzzzzzzzzz').remove()
            })
          });
        }
      }

      down();


    })

  }
}
